//#define USE_ARTAG

using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GoblinXNA;
using GoblinXNA.Graphics;
using GoblinXNA.SceneGraph;
using Model = GoblinXNA.Graphics.Model;
using GoblinXNA.Graphics.Geometry;
using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Vision;
using GoblinXNA.Device.Vision.Marker;
using GoblinXNA.Device.Util;
using GoblinXNA.Physics;
using GoblinXNA.Physics.Newton1;
using GoblinXNA.Sounds;
using GoblinXNA.Helpers;

using GoblinXNA.UI;
using GoblinXNA.UI.UI2D;
using GoblinXNA.Device.Generic;//keyboard



static class MENU		
	{
	    public const int BACK = 0;		
	    //Heirarchy 1		
	    public const int CREATE = 1;		
	    public const int MANIPULATE = 2;		
	    public const int SWITCHMODE = 3;		
	    //Heirarchy 2 - CREATE		
	    public const int CUBE = 4;		
	    public const int SPHERE = 5;		
	    //Heirarchy 2 - MANIPULATE		
	    public const int TRANSLATE = 6;		
	    public const int SCALE = 7;		
	    public const int ROTATE = 8;		
	    //Heirarchy 3 - MANIPULATE		
	    public const int XAXIS = 9;		
	    public const int YAXIS = 10;		
	    public const int ZAXIS = 11;		
	}


namespace Tutorial8___Optical_Marker_Tracking
{
    /// <summary>
    /// This tutorial demonstrates how to use both the ALVAR and ARTag optical marker tracker 
    /// library with our Goblin XNA framework. Please read the README.pdf included with this 
    /// project before running this tutorial. If you're using ARTag, please remove calib.xml
    /// from the solution explorer so that you can successfully build the project. 
    /// </summary>
    /// 	    // this is a class that I made to hold all the boolean variables that we use so that it is convenient ... Neerja		
	    // please transfer your previous ones to here, since it is static use the class names Flags.whatever		
	class Flags		
	{		
	    public static Boolean createMode = false;		
			
	}
    public class Tutorial8 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        Scene scene;
        MarkerNode groundMarkerNode, miniMapMarkerNode;
        GeometryNode groundNode;

        //menu
        MarkerNode hand1MarkerNode, hand2MarkerNode, hand3MarkerNode;
        TransformNode[] menuTransform;		
	    GeometryNode[] menuItems;

        //wall
        GeometryNode[] wallNode;
        TransformNode[] wallTransNode;
        Material[] wallMaterial;
        int wallindex = 0;
        int iniWallSize = 10;

        //travel
        TransformNode travelFirstTransNode, travelSecTransNode;
        float travelTranslationY = 0;
        bool travelMode = false;

        //miniMap
        double miniUpdateAngle, miniInitAngle, miniMapRotateDegree = 0;       
        bool miniMapUpdateOnce = false;

        //variables created by Neerja		
	    TransformNode testCubeTransNode = new TransformNode();		
        float distance;		
	    //end of variables created by Neerja

        //debug
        bool debug = true;

        //car by Sam
        GeometryNode carNode;
        TransformNode carTransNode;

        //car initial position
        float carTranslationX = 30f;
        float carTranslationY = -30f;
        float carTranslationZ = 5f;

        //car speed
        float carSpeed = 0f;
        float blurSpeed = 0.001f;//if current car speed is in the range of blurspeed, then set current to accurate speed
        float dashboardSpeed = 0f;
        const float dashToCarSpeed = .01f;        

        //car acceleration
        const float carAccel = .0004f; //car const acceleration
        const float groundResist = .0002f; //ground resistance
        const float carResist = .0002f; //car resistance. if carSpeed is negtive and dashboardSpeed is position, then carResist appears
        float carCurResist = 0f; //current car resistance in total, including groundResist and carResist
        float carCurAccel = 0f; //car current acceleration
        
        const int stop = 0;
        const int racing = 1;
        int carState = stop;

        RaceCar carsam;

        public Tutorial8()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Initialize the GoblinXNA framework
            State.InitGoblin(graphics, Content, "");

            // Initialize the scene graph
            scene = new Scene(this);

            // Use the newton physics engine to perform collision detection
            scene.PhysicsEngine = new NewtonPhysics();
            scene.PhysicsEngine.GravityDirection = new Vector3(0, 0, -1);
            //scene.PhysicsEngine.GravityDirection = (0, 0, 0);

            // For some reason, it causes memory conflict when it attempts to update the
            // marker transformation in the multi-threaded code, so if you're using ARTag
            // then you should not enable the marker tracking thread
#if !USE_ARTAG
            State.ThreadOption = (ushort)ThreadOptions.MarkerTracking;
#endif

            // Set up optical marker tracking
            // Note that we don't create our own camera when we use optical marker
            // tracking. It'll be created automatically
            SetupMarkerTracking();

            // Set up the lights used in the scene
            CreateLights();

            // Create the ground that represents the physical ground marker array
            CreateGround();

            // Create 3D objects
            CreateObjects();

            // Use per pixel lighting for better quality (If you using non NVidia graphics card,
            // setting this to true may reduce the performance significantly)
            //turn off
            //scene.PreferPerPixelLighting = true;
            scene.PreferPerPixelLighting = false;

            // Enable shadow mapping
            // NOTE: In order to use shadow mapping, you will need to add 'PostScreenShadowBlur.fx'
            // and 'ShadowMap.fx' shader files as well as 'ShadowDistanceFadeoutMap.dds' texture file
            // to your 'Content' directory
            //turn off
            //scene.EnableShadowMapping = true;
            scene.EnableShadowMapping = false;

            // Show Frames-Per-Second on the screen for debugging
            State.ShowFPS = true;
            State.ShowNotifications = true;

            // Add a keyboard press handler for user input
            KeyboardInput.Instance.KeyPressEvent += new HandleKeyPress(KeyPressHandler);

            base.Initialize();
        }

        private void CreateLights()
        {
            // Create a directional light source
            LightSource lightSource = new LightSource();
            lightSource.Direction = new Vector3(1, -1, -1);
            lightSource.Diffuse = Color.White.ToVector4();
            lightSource.Specular = new Vector4(0.6f, 0.6f, 0.6f, 1);

            // Create a light node to hold the light source
            LightNode lightNode = new LightNode();
            lightNode.LightSource = lightSource;

            scene.RootNode.AddChild(lightNode);
        }

        private void SetupMarkerTracking()
        {
            // Create our video capture device that uses DirectShow library. Note that 
            // the combinations of resolution and frame rate that are allowed depend on 
            // the particular video capture device. Thus, setting incorrect resolution 
            // and frame rate values may cause exceptions or simply be ignored, depending 
            // on the device driver.  The values set here will work for a Microsoft VX 6000, 
            // and many other webcams.
            DirectShowCapture captureDevice = new DirectShowCapture();
            captureDevice.InitVideoCapture(0, FrameRate._30Hz, Resolution._640x480,
                ImageFormat.R8G8B8_24, false);

            // Add this video capture device to the scene so that it can be used for
            // the marker tracker
            scene.AddVideoCaptureDevice(captureDevice);

            IMarkerTracker tracker = null;
            
#if USE_ARTAG
            // Create an optical marker tracker that uses ARTag library
            tracker = new ARTagTracker();
            // Set the configuration file to look for the marker specifications
            tracker.InitTracker(638.052f, 633.673f, captureDevice.Width,
                captureDevice.Height, false, "ARTag.cf");
#else
            // Create an optical marker tracker that uses ALVAR library
            tracker = new ALVARMarkerTracker();
            ((ALVARMarkerTracker)tracker).MaxMarkerError = 0.02f;
            tracker.InitTracker(captureDevice.Width, captureDevice.Height, "calib.xml", 9.0);
#endif

            // Set the marker tracker to use for our scene
            scene.MarkerTracker = tracker;

            // Display the camera image in the background. Note that this parameter should
            // be set after adding at least one video capture device to the Scene class.
            scene.ShowCameraImage = true;
        }

        private void CreateGround()
        {
            groundNode = new GeometryNode("Ground");
            groundNode.Model = new Box(100f, 130f, 0.1f);

            // Set this ground model to act as an occluder so that it appears transparent
            groundNode.IsOccluder = true;

            // Make the ground model to receive shadow casted by other objects with
            // CastShadows set to true
            groundNode.Model.ReceiveShadows = true;

            Material groundMaterial = new Material();
            groundMaterial.Diffuse = Color.Gray.ToVector4();
            groundMaterial.Specular = Color.White.ToVector4();
            groundMaterial.SpecularPower = 20;

            groundNode.Material = groundMaterial;

            // groundMarkerNode.AddChild(groundNode);
        }

        private void CreateObjects()
        {
            //NewtonPhysics physicsEngine = (NewtonPhysics)scene.PhysicsEngine;

            wallNode = new GeometryNode[100];
            wallMaterial = new Material[100];
            wallTransNode = new TransformNode[100];

            createAllMarkers();

            //Create the marker node for the minimap
            miniMapMarkerNode = new MarkerNode(scene.MarkerTracker, "1-4_ALVAR_MiniMap.txt");
            scene.RootNode.AddChild(miniMapMarkerNode);

            travelFirstTransNode = new TransformNode("travelFirstTransNode");
            travelSecTransNode = new TransformNode("travelSecTransNode");
            groundMarkerNode.AddChild(travelFirstTransNode);
            travelFirstTransNode.AddChild(travelSecTransNode);
            travelSecTransNode.AddChild(groundNode);
            initMap();

            // Add a race car
            //car = VehicleCreator.AddRaceCar(scene, travelSecTransNode);
            //NewtonVehicle car = new IPhysicsObject();
            //xueying
            //carNode = new GeometryNode("car");
            //carNode.Model = new Box(8);

            //carNode.Physics.MaterialName = "car";
            //carNode.Physics.Interactable = true;
            //carNode.Physics.Collidable = true;
            //carNode.Physics.Shape = GoblinXNA.Physics.ShapeType.Box;
            //carNode.Physics.Mass = 60f;
            //carNode.AddToPhysicsEngine = true;
            ////carNode.Physics.InitialLinearVelocity = new Vector3(300, 0, 0);
            ////carNode.Physics.Container = carNode;

            //carNode.Model.CastShadows = true;
            //carNode.Model.ReceiveShadows = true;

            //Material carMaterial = new Material();
            //carMaterial.Diffuse = new Vector4(0.6f, 0.5f, 0.5f, 0.8f);
            //carMaterial.Specular = Color.White.ToVector4();
            //carMaterial.SpecularPower = 10;
            //carNode.Material = carMaterial;
            //carTransNode = new TransformNode();
            //carTransNode.Translation = new Vector3(carTranslationX, carTranslationY, carTranslationZ);

            //groundNode.AddChild(carTransNode);
            //carTransNode.AddChild(carNode);

            //// Add a race car
            TransformNode parentTransNode = new TransformNode("parentNode");
            parentTransNode.Translation = new Vector3(10, -20, 0);
            travelFirstTransNode.AddChild(parentTransNode);
            carsam = VehicleCreator.AddRaceCar(scene, parentTransNode);
            carsam.LinearDamping = .01f;
            

            GeometryNode realgroundNode = new GeometryNode("RealGround");
            realgroundNode.Model = new Box(90, 120, 1f);

            realgroundNode.Physics.MaterialName = "RealGround";
            // Make this ground plane collidable, so other collidable objects can collide
            // with this ground
            realgroundNode.Physics.Collidable = true;
            realgroundNode.Physics.Shape = GoblinXNA.Physics.ShapeType.Box;
            realgroundNode.AddToPhysicsEngine = true;

            realgroundNode.Model.CastShadows = true;
            realgroundNode.Model.ReceiveShadows = true;
            Material realgroundMaterial = new Material();
            realgroundMaterial.Diffuse = Color.Gray.ToVector4();
            realgroundMaterial.Specular = Color.White.ToVector4();
            realgroundMaterial.SpecularPower = 10;
            realgroundNode.Material = realgroundMaterial;
            TransformNode realgroundTransNode = new TransformNode();
            realgroundTransNode.Translation = new Vector3(40, -58, 0);
            groundNode.AddChild(realgroundTransNode);
            realgroundTransNode.AddChild(realgroundNode);

            //menu
            initHandMenu();

             //my test cube		
            GeometryNode testCubeNode = new GeometryNode("testCube");		
            testCubeNode.Model = new Box(10);		
            Material testMat = new Material();		
            testMat.Diffuse = Color.AliceBlue.ToVector4();		
            testMat.Specular = Color.White.ToVector4();		
            testMat.SpecularPower = 20;		
            testCubeNode.Material = testMat;		
		
            testCubeTransNode = new TransformNode();		
			
            testCubeTransNode.AddChild(testCubeNode);		
            hand1MarkerNode.AddChild(testCubeTransNode);
        }

        private void createAllMarkers()
        {
            //Ground Marker
            groundMarkerNode = new MarkerNode(scene.MarkerTracker, "20-59_ALVAR_groundArray.txt");
            //groundMarkerNode = new MarkerNode(scene.MarkerTracker, "25-60_ALVARArray_groundArray.txt");
            scene.RootNode.AddChild(groundMarkerNode);

            //Hand Markers
            hand1MarkerNode = new MarkerNode(scene.MarkerTracker, "ALVAR_Hand1.txt"); //Menu
            hand2MarkerNode = new MarkerNode(scene.MarkerTracker, "ALVAR_Hand2.txt"); //Start/Stop
            hand3MarkerNode = new MarkerNode(scene.MarkerTracker, "ALVAR_Hand3.txt"); //pointer

            scene.RootNode.AddChild(hand1MarkerNode); //Menu
            scene.RootNode.AddChild(hand2MarkerNode); //Start/Stop
            scene.RootNode.AddChild(hand3MarkerNode); //Pointer
        }

        private void initHandMenu()
        {
            //Create all heirarchies of menu. Add only the first heirarchy to the scene.
            menuTransform = new TransformNode[5];
            //Thumb
            menuTransform[0] = new TransformNode();
            menuTransform[0].Translation = new Vector3(-30, -20, 0);
            hand1MarkerNode.AddChild(menuTransform[0]);
            //Index finger

            //hand3MarkerNode.AddChild(menuTransform[1]);
            //hand3MarkerNode.AddChild(menuTransform[2]);
            //hand3MarkerNode.AddChild(menuTransform[3]);
            //hand3MarkerNode.AddChild(menuTransform[4]);


            menuItems = new GeometryNode[15];

            menuItems[1] = new GeometryNode("CREATE");
            menuItems[1].Model = new Box(10, 10, 1);
            Material itemMaterial = new Material();
            itemMaterial.Diffuse = Color.Blue.ToVector4();
            itemMaterial.Specular = Color.White.ToVector4();
            menuItems[1].Material = itemMaterial;
            menuTransform[0].AddChild(menuItems[1]);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            Content.Unload();
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            //travelFirstTransNode.Translation = new Vector3(0, travelTranslationY, 0);
            //carSpeedControl();

            if (travelMode == true)
                travelFirstTransNode.Scale = new Vector3(5, 5, 5);
            else
            {
                travelFirstTransNode.Scale = new Vector3(1, 1, 1);

                /*		
                ** @Neerja: Object creation starts here, when createMode flag is true		
                ** TODO: change trigger and generalize for createMode after Ketaki is done with menu		
                */		
			
	
                if (Flags.createMode && hand3MarkerNode.MarkerFound) // triggered with pressing C on keyboard		
                {		
                    //Notifier.AddMessage("say aa" + distance);		
                    distance = System.Math.Abs(hand1MarkerNode.WorldTransformation.Translation.X - hand3MarkerNode.WorldTransformation.Translation.X);		
                    if (distance > 0)		
                    {		
                        testCubeTransNode.Scale = new Vector3(distance * 0.1f);		
                    }		
                }		
                //else	
	

                // Flags.createMode = false;
            }


            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            //If car is not null and already added to the physics engine
            if (carsam != null && ((NewtonPhysics)scene.PhysicsEngine).GetBody(carsam) != IntPtr.Zero)
            {
                // Gets the keyboard state
                KeyboardState keyboard = Keyboard.GetState();

                // Control the car steering with right and left arrow keys
                if (keyboard.IsKeyDown(Keys.Right))
                    carsam.SetSteering(-1);
                    //carsam.SetSteering((float)miniMapRotateDegree);
                else if (keyboard.IsKeyDown(Keys.Left))
                    carsam.SetSteering(1);
                    //carsam.SetSteering((float)-miniMapRotateDegree);
                else
                    carsam.SetSteering(0);

                // Control the car's forward torque with up and down arrow keys
                if (keyboard.IsKeyDown(Keys.Up))
                    carsam.SetTireTorque(100);
                else if (keyboard.IsKeyDown(Keys.Down))
                    carsam.SetTireTorque(-100);
                else
                    carsam.SetTireTorque(0);

                // Control the hand brake with space key
                if (keyboard.IsKeyDown(Keys.Space))
                    carsam.ApplyHandBrakes(1);
                else
                    carsam.ApplyHandBrakes(0);
            }
            






            // If ground marker array is detected
            //if (groundMarkerNode.MarkerFound)
            //{
            //    //// If the toolbar marker array is detected, then overlay the box model on top
            //    //// of the toolbar marker array; otherwise, overlay the box model on top of
            //    //// the ground marker array
            //    //if (false)
            //    //{
            //    //}
            //    //else
            //    //    ((NewtonPhysics)scene.PhysicsEngine).SetTransform(wallNode[0].Physics,
            //    //        Matrix.CreateTranslation(Vector3.One * 4));
            //    ;
            //}

            // TODO: Add your drawing code here

            if (groundMarkerNode.MarkerFound)
            {
                if (miniMapMarkerNode.MarkerFound)
                {
                    Console.WriteLine("found!!!");
                    if (!miniMapUpdateOnce)
                    {
                        UpdateMiniMapAngle();
                        miniInitAngle = miniUpdateAngle;
                        miniMapUpdateOnce = true;
                    }
                    else
                    {
                        //if (travelMode)
                        //{
                        UpdateMiniMapAngle();
                        double deltAngle = miniUpdateAngle - miniInitAngle;
                        miniMapRotateDegree += deltAngle * 0.01;
                        // Vector3 miniMapPos=Vector3.Transform(new Vector3(0, 0, 0), groundNode.WorldTransformation * 
                        //     Matrix.Invert(miniMapMarkerNode.WorldTransformation));
                        travelFirstTransNode.Translation = new Vector3(30, -30, 0);
                        travelFirstTransNode.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, (float)miniMapRotateDegree);
                        travelSecTransNode.Translation = new Vector3(-30, 30, 0);
                        miniInitAngle = miniUpdateAngle;
                        // }
                    }
                }
            }

            //// If car is not null and already added to the physics engine
            //if (car != null && ((NewtonPhysics)scene.PhysicsEngine).GetBody(car) != IntPtr.Zero)
            //{
            //    // Gets the keyboard state
            //    KeyboardState keyboard = Keyboard.GetState();

            //    // Control the car steering with right and left arrow keys
            //    if (keyboard.IsKeyDown(Keys.Right))
            //        car.SetSteering(-1);
            //    else if (keyboard.IsKeyDown(Keys.Left))
            //        car.SetSteering(1);
            //    else
            //        car.SetSteering(0);

            //    // Control the car's forward torque with up and down arrow keys
            //    if (keyboard.IsKeyDown(Keys.Up))
            //        car.SetTireTorque(1);
            //    else if (keyboard.IsKeyDown(Keys.Down))
            //        car.SetTireTorque(-1);
            //    else
            //        car.SetTireTorque(0);

            //    // Control the hand brake with space key
            //    if (keyboard.IsKeyDown(Keys.Space))
            //        car.ApplyHandBrakes(1);
            //    else
            //        car.ApplyHandBrakes(0);
            //}

            //Samcar
            //travelFirstTransNode.Translation = new Vector3(0, travelTranslationY, 0);
            //carNode.Physics.PhysicsWorldTransform = Matrix.CreateTranslation(carTranslationX, carTranslationY, carTranslationZ);
            //carTransNode.Translation = new Vector3(carTranslationX, carTranslationY, carTranslationZ);

            base.Draw(gameTime);
        }

        //Update minimap's rotation angle respect to the ground--by Sheryn
        private void UpdateMiniMapAngle()
        {
            Vector3 miniBaseVector = new Vector3(1, 0, 0);
            Vector3 miniControlVector = Vector3.Transform(new Vector3(1, 0, 0), groundMarkerNode.WorldTransformation * Matrix.Invert(miniMapMarkerNode.WorldTransformation)) -
                Vector3.Transform(new Vector3(0, 0, 0), groundMarkerNode.WorldTransformation * Matrix.Invert(miniMapMarkerNode.WorldTransformation));
            miniControlVector.Z = 0; miniControlVector.Normalize();
            miniUpdateAngle = 180 * System.Math.Acos(Vector3.Dot(miniBaseVector, miniControlVector)) / System.Math.PI;

            Console.WriteLine(miniControlVector);
            Console.WriteLine(Vector3.Dot(miniBaseVector, miniControlVector));
            Console.WriteLine(miniUpdateAngle);
        }

        protected void initMap()
        {
            //outer square
            createWall(0, 0, 90f, 2f, 10f);//short edge at origin
            createWall(0, -110, 2f, 110f, 10f);// long edge at origin
            createWall((float)(9.0 - .2) * iniWallSize, -11 * iniWallSize, 2f, 110f, 10f);//long edge
            createWall(0, -110, 90f, 2f, 10f);//short edge

            //inner edge
            createWall((float)(9.0 - .2) * iniWallSize / 4, -8 * iniWallSize, 2f, 80f, 10f);
            createWall((float)(9.0 - .2) * iniWallSize * 2 / 4, -11 * iniWallSize, 2f, 80f, 10f);
            createWall((float)(9.0 - .2) * iniWallSize * 3 / 4, -8 * iniWallSize, 2f, 80f, 10f);
        }

        protected void createWall(float TranslationX, float TranslationY, float sizeX, float sizeY, float sizeZ)
        {
            //float TranslationXTemp = (iniWallSize * ScaleX - iniWallSize) / 2 + TranslationX;
            //float TranslationYTemp = (iniWallSize * ScaleY - iniWallSize) / 2 + TranslationY;
            float TranslationXTemp = (sizeX - iniWallSize) / 2 + TranslationX;
            float TranslationYTemp = (sizeY - iniWallSize) / 2 + TranslationY;

            // Create a geometry node with a model of a box that will be overlaid on
            // top of the ground marker array initially. (When the toolbar marker array is
            // detected, it will be overlaid on top of the toolbar marker array.)            
            wallNode[wallindex] = new GeometryNode("wall" + wallindex);
            //wallNode[wallindex].Model = new Box(iniWallSize);
            wallNode[wallindex].Model = new Box(sizeX, sizeY, sizeZ);

            // Make the sphere models interactable, which means that they
            // participate in the physical simulation
            wallNode[wallindex].Physics.Interactable = true;            
            wallNode[wallindex].Physics.Collidable = true;
            wallNode[wallindex].Physics.Shape = ShapeType.Box;
            wallNode[wallindex].Physics.Mass = 1000f;
            wallNode[wallindex].AddToPhysicsEngine = true;

            // Make this box model cast and receive shadows
            wallNode[wallindex].Model.CastShadows = true;
            wallNode[wallindex].Model.ReceiveShadows = true;

            // Create a material to apply to the box model
            wallMaterial[wallindex] = new Material();
            wallMaterial[wallindex].Diffuse = Color.Green.ToVector4();
            wallMaterial[wallindex].Specular = Color.White.ToVector4();
            wallMaterial[wallindex].SpecularPower = 10;

            wallNode[wallindex].Material = wallMaterial[wallindex];




            wallTransNode[wallindex] = new TransformNode("wallTransNode" + wallindex);
            wallTransNode[wallindex].Translation = new Vector3(TranslationXTemp, TranslationYTemp, 5f);
            //wallTransNode[wallindex].Scale = new Vector3(ScaleX, ScaleY, 1);
            

            if (debug)
                Console.WriteLine(wallTransNode[wallindex].Name + "!!!!!!!!!!!!!!!!!!!!!!1");

            // Add this box model node to the ground marker node
            groundNode.AddChild(wallTransNode[wallindex]);
            wallTransNode[wallindex].AddChild(wallNode[wallindex]);

            wallindex++;
        }

        //keyboard operation for debugging
        private void KeyPressHandler(Keys keys, KeyModifier modifier)
        {
            // Detect key press "t"
            if (keys == Keys.T)
                travelMode = true;

            if (keys == Keys.N)
                travelMode = false;

            //debuging Sam car speed control
            if (keys == Keys.D1)
            {
                Console.WriteLine("press 1");
                carState = racing;
                dashboardSpeed = 1f;
            }
            else if (keys == Keys.D2)
            {
                carState = racing;
                dashboardSpeed = 2f;
            }
            else if (keys == Keys.D0)
            {
                carState = racing;
                dashboardSpeed = 0f;
            }
            else if (keys == Keys.D9)
            {
                carState = racing;
                dashboardSpeed = 9f;
            }

            else if (keys == Keys.D5)
            {
                carState = racing;
                dashboardSpeed = -5f;
            }
            else if (keys == Keys.D7)
            {
                carState = racing;
                dashboardSpeed = -7f;
            }

            if (keys == Keys.C)
                Flags.createMode = true;
        }

        private void carSpeedControl()
        {
            if (carState == racing)
            {
                if ((carSpeed >= 0 && dashboardSpeed >= 0) || (carSpeed <= 0 && dashboardSpeed <= 0))
                    carCurResist = groundResist;
                else if(carSpeed >= 0 && dashboardSpeed <= 0)
                    carCurResist =  groundResist + carResist;
                else if (carSpeed <= 0 && dashboardSpeed >= 0)
                    carCurResist = 0;//I know it's wierd but it works

                
                if (carSpeed < (dashboardSpeed * dashToCarSpeed - blurSpeed))
                    carCurAccel = carAccel - carCurResist;
                else if (carSpeed > (dashboardSpeed * dashToCarSpeed - blurSpeed) && carSpeed < (dashboardSpeed * dashToCarSpeed + blurSpeed))
                {
                    carCurAccel = 0;
                    carSpeed = dashboardSpeed * dashToCarSpeed;
                }
                else if (carSpeed > (dashboardSpeed * dashToCarSpeed + blurSpeed))
                    carCurAccel = -carCurResist;
                

                carSpeed = carSpeed + carCurAccel;
                carTranslationY = carTranslationY + carSpeed;
            }
            Console.WriteLine("carSpeed:  " + carSpeed + "    carCurAccel: " + carCurAccel);
        }

























    }
}
